from datetime import datetime
from decimal import Decimal
from random import randint

from django.db import transaction
from rest_framework import serializers
from rest_framework.fields import SerializerMethodField
from rest_framework.serializers import ModelSerializer

from shopping.models import Classification, Commodity, CommodityImg, ShoppingCart, Order, OrderGoods, Payment
from users.models import Address


class ClassificationSerializer(ModelSerializer):
    class Meta:
        model = Classification
        fields = "__all__"


# 一级分类的序列化器
class ParentClassificationSerializer(ModelSerializer):
    # 添加一个子级分类的字段
    classification_set = ClassificationSerializer(many=True, read_only=True)

    class Meta:
        model = Classification
        fields = ["id", "name", "classification_set"]


class CommodityImgSerializer(ModelSerializer):
    class Meta:
        model = CommodityImg
        fields = ["src"]


class CommoditySerializer(ModelSerializer):
    # 商品分类
    classification1_name = serializers.CharField(source='classification1.name', read_only=True)
    classification2_name = serializers.CharField(source='classification2.name', read_only=True)
    # 商品图片
    commodityimg_set = CommodityImgSerializer(many=True, read_only=True)

    class Meta:
        model = Commodity
        exclude = ["is_delete"]

        extra_kwargs = {
            "sales": {"read_only": True},
            "comments": {"read_only": True}
        }


class ShoppingCartSerializer(ModelSerializer):
    # commodity_detail = CommoditySerializer(read_only=True,many=True)

    commodityDetail = SerializerMethodField()

    def get_commodityDetail(self, shoppingcart):
        """

        :param shoppingcart: shoppingcart实例对象（模型对象）
        :return: 购物车管理的商品信息
        """
        return CommoditySerializer(shoppingcart.commodity).data

    class Meta:
        model = ShoppingCart
        fields = '__all__'

    def validate(self, attrs):
        # user = self.context["request"].user
        # # 查看当前登录的用户id与测试页表单提交的用户id
        # print(user.id, attrs['user'].id)
        # # 查看id值是否一致 如果不一致则代表不是同一个用户
        # print(user.id == attrs['user'].id)
        # if user.id != attrs["user"].id:
        #     raise serializers.ValidationError("非法请求")
        if attrs["number"] <= 0:
            raise serializers.ValidationError("要购买的商品数量错误")
        # 要购买的商品数量大于商品的库存
        elif attrs["number"] > attrs['commodity'].stock:
            raise serializers.ValidationError("商品数量超出库存值")
        else:
            return attrs


class OrderSerializer(ModelSerializer):
    # 客户端传入要结算的商品id 列表
    cart = serializers.ListField(write_only=True)

    def create(self, validated_data):
        """
        重写订单创建方法
        客户端会传递要结算的购物车商品id 支付方式 收货地址id
        :param validated_data:  用户传入的数据
        :return:
        """
        # 生成订单编号 唯一 时间+格式化6位用户的id+两位随机数
        # 获取到用户
        user = self.context["request"].user
        user_id = '%06d' % user.id
        # 获取到当前的时间戳 把日期格式化成自定义的规则
        # 把时间戳+用户id+随机数拼接起来
        order_id = datetime.now().strftime('%Y%m%d%H%M%S') + user_id[:6] + '%02d' % randint(1, 99)

        # 获取客户端传入的支付方式
        pay_method = validated_data.get('pay_method')

        # 获取客户端收货地址id
        try:
            # 通过客户端传递过来的id，获取收货地址信息 模型对象
            address = Address.objects.get(id=validated_data.get('address'))
        except Address.DoesNotExist:
            raise serializers.ValidationError('address error')
        # 收货地址详细信息拼接
        # 湖南省 长沙市 岳麓区 详情地址 xx街道 xx小区xx栋 用户收 电话号码
        address_s = f'{address.province.name} {address.city.name}' \
                    f' {address.district.name} {address.place} 【{address.receiver}】收 ' \
                    f'Tel：{address.mobile}'

        with transaction.atomic():
            # 开启事务 在with里面的代码执行完毕后会自动关闭事务
            # 创建一个保存点
            save_point = transaction.savepoint()
            try:
                # 初始化订单表 接待新一位用户的到来
                order = Order.objects.create(
                    order_id=order_id,
                    total_count=0,
                    total_amount=Decimal('0.00'),
                    pay_method=pay_method,
                    # 根据用户提交的支付方式来决定
                    # 1为支付宝  待支付的状态
                    # 2为货到付款 待发货的状态
                    status=1 if pay_method == 1 else 2,
                    address=address_s,
                    user=user,

                )
                # 用户把购物车的商品依次拿出来
                # 记录商品信息 计算商品数量和总额

                # 得到购物车对象
                carts = validated_data.get("cart")
                for cart_id in carts:
                    # 一直尝试对商品做结算的操作
                    while True:
                        try:
                            cart = ShoppingCart.objects.get(id=cart_id)
                        except ShoppingCart.DoesNotExist:
                            raise serializers.ValidationError("购物信息不存在")

                        # 得到购物车的商品对象
                        commodity = cart.commodity
                        # 记录原本的商品库存数量和销量
                        origin_stock = commodity.stock
                        origin_sales = commodity.sales

                        # 校验 核算购买的商品数量是否超过库存
                        if cart.number > origin_stock:
                            raise serializers.ValidationError("库存不足")

                        # 更新商品信息 库存跟销量
                        new_stock = origin_stock - cart.number
                        new_sales = origin_sales + cart.number

                        # 更新商品表
                        # commodity.stock = new_stock
                        # commodity.sales = new_sales
                        # commodity.save()

                        # 根据获取到的商品id查询对应的库存，做修改的操作
                        # 库存发生了改变的情况下，查询不到商品对象了
                        res = Commodity.objects.filter(id=commodity.id, stock=origin_stock).update(stock=new_stock,
                                                                                                   sales=new_sales)
                        # 如果更新的操作没有成功
                        if not res:
                            continue

                        # 订单详情数据记录 小票
                        OrderGoods.objects.create(
                            number=cart.number,
                            price=commodity.price,
                            order=order,
                            commodity=commodity
                        )

                        # 更新订单表
                        order.total_count += cart.number
                        order.total_amount += (cart.number * commodity.price)
                        break

                    order.save()

                    # 结算成功删除已结算购物车中的信息
                ShoppingCart.objects.filter(id__in=carts).delete()
            except Exception as e:
                # 发生异常，回滚到保存点的位置
                transaction.savepoint_rollback(save_point)
                raise serializers.ValidationError(e)
            else:
                # 没有异常提交事务
                transaction.savepoint_commit(save_point)
        return order

    class Meta:
        model = Order
        fields = '__all__'
        read_only_fields = ["order_id", "total_count", "total_amount", "status", "user"]


'''
商品添加到购物车
提交订单
生成订单编号
获取客户端传入的信息，支付方式 收货地址
初始化订单（刚结算完上一个客户，在新客户来之前，把收银台清理干净）
得到购物车里面的每个商品，更新商品表，创建登记订单商品表
更新订单表，保存订单信息
删除购物车内已结算的商品
购物车商品管理

'''
class PaymentSerializer(ModelSerializer):
    class Meta:
        model=Payment
        fields="__all__"